// gorpc/server/server.go

package server

import (
	"fmt"
	"gorpc/codec"
	"gorpc/common"
	"gorpc/protocol"
	"reflect"
)

type HandlerFunc func(*protocol.Message) *protocol.Message

type RPCServer struct {
	handlers map[string]HandlerFunc
}

func NewServer() *RPCServer {
	return &RPCServer{
		handlers: make(map[string]HandlerFunc),
	}
}

// Register 注册服务方法（暴露给业务方） Deprecated
func (s *RPCServer) Register(method string, handler HandlerFunc) {
	s.handlers[method] = handler
}

// Dispatch 请求分发（供transport层调用）
func (s *RPCServer) Dispatch(req *protocol.Message) (*protocol.Message, error) {
	handler, exists := s.handlers[req.Header.ServiceMethod]
	if !exists {
		return s.buildErrorResponse(
			common.ErrorCodeServiceNotFound,
			"method "+req.Header.ServiceMethod+" not registered"), common.ErrServiceNotFound
	}
	return handler(req), nil
}

func (s *RPCServer) buildErrorResponse(code int, msg string) *protocol.Message {
	return &protocol.Message{
		Header: &protocol.Header{
			Error: common.NewRPCError(code, msg, nil).Error(),
		},
	}
}

// RegisterService gorpc/server/server.go
func (s *RPCServer) RegisterService(service interface{}) {
	val := reflect.ValueOf(service)
	serviceType := val.Type()
	for i := 0; i < serviceType.NumMethod(); i++ {
		method := serviceType.Method(i)
		fmt.Println("method: ", method.Name)
		s.handlers[method.Name] = s.createHandler(service, method)
	}
}

func (s *RPCServer) createHandler(service interface{}, method reflect.Method) HandlerFunc {
	return func(req *protocol.Message) *protocol.Message {
		// 反序列化请求参数
		var args common.CalcArgs
		if err := req.DeserializeBody(&args); err != nil {
			return s.buildErrorResponse(common.ErrorCodeSerialization, err.Error())
		}

		// 反射调用方法
		in := []reflect.Value{
			reflect.ValueOf(service),
			reflect.ValueOf(args.A),
			reflect.ValueOf(args.B),
		}
		out := method.Func.Call(in)

		// 处理结果和错误
		resp := protocol.NewMessage("")
		if err, ok := out[1].Interface().(error); ok && err != nil {
			resp.Header.Error = err.Error()
		} else {
			reply := &common.CalcReply{Result: out[0].Interface().(int)}
			resp.SerializeBody(reply, codec.CodecType(req.SerializerCode))
		}
		return resp
	}
}
